
local TIME_DURATIONS = {
    SHORT = 5,
    LONG = 40,
};
-- areaplanner ---------------------------------------------
local imgareaplanner = "areahelper_planner.png";
local imgtemplatewritten = "areahelper_template.png";

minetest.register_craftitem("areahelper_planner:areaplanner", {
    description = "Plantilla para anotar una definición de area.",
    -- inventory_image = minetest.inventorycube(imgyellow, imgyellow, imgyellow    ),
    inventory_image = imgareaplanner,
    groups = {areahelper = 1, tool = 1},
    stackable = true,
    on_use = function (itemstack, user, pointed_thing)
        local inv = user:get_inventory(); -- inventario del usuario.
        
        
        
        -- LLAMAR AL FORMSPEC.amount
        -- TODO - HACER CHECK DE PERMISOS Y QUE NO SALGA EL FORMULARIO.
        local habilitado, miss = minetest.check_player_privs(user, areas.adminPrivs);
        if (not habilitado) then
            minetest.chat_send_player(user:get_player_name(), "No tiene suficiente permiso para utilizar el item");
            return itemstack;
        end

        local cabecera = "Marcar extensión del area";
        local form = {
            areahelper.dimensionformspec,
            "label[0.375,0.50;", minetest.formspec_escape(cabecera), "]",
            "field[0.375,1.25;2 ,0.8;ancho;Ancho;]",
            "field[0.375,2.50.25;2,0.8;largo;Largo;]",
            "field[0.375,3.75;2,0.8;alto;Alto;]",

            "field[6    ,1.25;2,0.8;soterrado;Soterrado;]",
            "field[6    ,2.50;4,0.8;descriptor;Tag;]",
            "field[6    ,3.75;2,0.8;amount;Cantidad;]",
            "button_exit[4.5,5;3,0.8;setear;Setear]"
        };

        local salida = minetest.show_formspec(user:get_player_name(), "areahelper_planner:plannerform", table.concat(form, ""));
        
        -- RECIBIR LOS DATOS DEL FORMSPEC Y ALMACENARLOS EN EL OBJETO DE SALIDA DEBE OCUURIR EN EL CALLBACK.
        return itemstack;
    end,
    --[[tool_capabilities = {
        full_punch_interval = 1.5,
        max_drop_level = 1,
        groupcaps = {
        },
        damage_groups = {},
    },
    ]]--
    
});

minetest.register_on_player_receive_fields(function(player, formname, fields)
    
    -- GUARDAS
    if formname ~= "areahelper_planner:plannerform" then return; end
        -- check de privilegios
    local valid, miss = minetest.check_player_privs(player, areas.adminPrivs);
    if not valid then return; end
    
    -- validacion campos
    
    local CAMPOSVALIDOS, fields, mensaje = camposValidos(fields);
    if not CAMPOSVALIDOS then
        minetest.chat_send_player(player:get_player_name(), mensaje)
        return;
    end
    
    -- --------- POSICION DEL JUGADOR Y GENERACION DEL MARCADOR --------------------
    -- La función emplea los campos anotados pero calcula las posiciones del area también empleando la orientacion horizontal.
    local pos1, pos2 = calcularPosiciones(player, fields);
    generateMarker(pos1, pos2);
    
    --TODO CREACION DEL OBJETO CON LA INFO 
    local nuevoobjeto = ItemStack("areahelper_planner:template_writen " .. fields.amount);
    local metas = nuevoobjeto:get_meta();
    
    metas:set_string("ancho", fields.ancho )
    metas:set_string("largo", fields.largo )
    metas:set_string("alto" , fields.alto  )
    metas:set_string("soterrado", fields.soterrado )
    metas:set_string(
        "description"
        , table.concat(
            {
            "Template:"
            , fields.descriptor
            , "\n(ancho x largo x alto) - vertical :"
            , "(" .. table.concat({fields.ancho
                                , fields.largo
                                , fields.alto}
                                ," x ") .. ") -"
            , fields.soterrado
            }
            , " "
        )
    ); 
                 
                
    metas:set_string("short_description", "Template." .. (fields.descriptor or ""));
    -- metas:set_string("pos1", minetest:from_table(pos1))
    -- metas:set_string("pos2", minetest:from_table(pos2))
    metas:set_string("pos1", minetest.pos_to_string(pos1))
    metas:set_string("pos2", minetest.pos_to_string(pos2))
    
    -- PONERLO EN EL INVENTARIO O LANZARLO
    local inv = player:get_inventory();
    local sobrante = inv:add_item("main", nuevoobjeto);
    if sobrante:get_count() > 0 then
        minetest.item_drop(sobrante, player, player:get_pos());
    end;

    --TODO TODO BORRADO DE 1 unidad de la mano del jugador.
    return nil; -- No cambiar el objeto de la mano. -- ¿?¿¿?¿?
    
end)

-- Funciones encapsuladas del formulario
function camposValidos(fields)
    local valid = true;
    local message = "OK";

    if (fields.largo == nil or
     fields.ancho == nil or 
     fields.alto == nil or 
     fields.soterrado == nil)
    then
    -- if ( string.len(fields.largo) == 0) or      -- then fields.largo = 1; end
    --  (string.len(fields.ancho) == 0)  or    -- then fields.ancho = 1; end
    --  (string.len(fields.alto )  == 0)  or   -- then fields.alto  = 1; end
    --  (string.len(fields.soterrado) == 0) then-- then fields.soterrado = 1; end
        valid = false
        message = "Los campos deben ser informados"
    end

    if (fields.amount == nil or string.len(fields.amount) == 0) then  fields.amount = 1; end

    -- TODO alguna validacion para fields.descriptor
    return valid, fields, message;

    -- devuelve BOOLEANO, campos actualizados, mensaje.
end

function calcularPosiciones(jugador, fields)
    
    --[[
            ........|ancho
            ........v
        X-> .largo->
    
                --  pos1                -- pos2  
    -- eje x    pos.x + inix       | pos.x + deltax
    -- eje z    pos.z + iniz       | pos.z + deltaz
    -- eje y -> pos.y - soterrado  | pos.y + alto - soterrado
    ]]--
    local look_dir = 360-math.deg(jugador:get_look_horizontal()) % 360;
    local inix, iniz, deltax, deltaz;
    if (look_dir >= 315 or look_dir < 45) then -- +Z
        inix   = 0;
        iniz   = 1;
        deltax = fields.ancho - 1;
        deltaz = fields.largo - 1;
    elseif (look_dir >= 45 and look_dir < 135) then -- +X
        inix   = 1;
        iniz   = 1;
        deltax = fields.largo-1;
        deltaz = -(fields.ancho-1);
    elseif (look_dir >= 135 and look_dir < 225) then  -- -Z
        inix   = 0;
        iniz   = 0;
        deltax = -(fields.ancho-1);
        deltaz = -(fields.largo-1);
    elseif (look_dir >= 225 and look_dir < 315) then  -- -X
        inix   = 0;
        iniz   = 0;
        deltax = -(fields.largo-1);
        deltaz = (fields.ancho-1);
    else
        inix   = 0;
        iniz   = 0;
        deltax = 0;
        deltaz = 0;
    end

    local pos = jugador:get_pos();
    local pos1, pos2 = {}, {};
    pos1.x = math.floor(pos.x) + inix
    pos1.y = pos.y - fields.soterrado
    pos1.z = math.floor(pos.z) + iniz
    pos2.x = math.floor(pos.x) + inix + deltax
    pos2.y = pos.y + (fields.alto - 1) - fields.soterrado
    pos2.z = math.floor(pos.z) + iniz + deltaz

    pos1.y = math.ceil(tonumber(pos1.y) + 0.5);
    pos2.y = math.ceil(tonumber(pos2.y) + 0.5);
    pos1, pos2 = areas:sortPos(pos1, pos2) -- se ponen en orden las dos posiciones.

    return pos1, pos2;
end

function generateMarker(pos1, pos2, duracion) -- code taken and adapted from worldedit
    if duracion == nil then duracion = TIME_DURATIONS.SHORT; end

    
    local vec = vector.subtract(pos2, pos1)
    local maxside = math.max(vec.x, math.max(vec.y, vec.z))
    local limit = tonumber(4) * 16 -- el 4 es: minetest.settings:get("active_object_send_range_blocks")
    if maxside > limit * 1.5 then
        -- The client likely won't be able to see the plane markers as intended anyway,
        -- thus don't place them and also don't load the area into memory
        return
    end

    local thickness = 0.2
    local sizex, sizey, sizez = (1 + pos2.x - pos1.x) / 2, (1 + pos2.y - pos1.y) / 2, (1 + pos2.z - pos1.z) / 2

    --make area stay loaded
    local manip = minetest.get_voxel_manip()
    manip:read_from_map(pos1, pos2)

    local markers = {}
    -- local init_sentinel = table.concat({_duracion = duracion}, "");
    -- minetest.log("Init_sentinel " .. init_sentinel);
    --XY plane markers
    for _, z in ipairs({pos1.z - 0.5, pos2.z + 0.5}) do
        local entpos = {x=pos1.x + sizex - 0.5, y=pos1.y + sizey - 0.5, z=z}
        
        local marker = minetest.add_entity(entpos, "areahelper:markerentity", init_sentinel)
        if marker ~= nil then
            marker:set_properties({
                visual_size={x=sizex * 2, y=sizey * 2},
                collisionbox = {-sizex, -sizey, -thickness, sizex, sizey, thickness},
                --_duracion = duracion,
            })
            marker:get_luaentity():queue_delete(duracion);
            marker:get_luaentity().player_name = name
            table.insert(markers, marker)
        end
    end

    --YZ plane markers
    for _, x in ipairs({pos1.x - 0.5, pos2.x + 0.5}) do
        local entpos = {x=x, y=pos1.y + sizey - 0.5, z=pos1.z + sizez - 0.5}
        local marker = minetest.add_entity(entpos, "areahelper:markerentity", init_sentinel)
        if marker ~= nil then
            marker:set_properties({
                visual_size={x=sizez * 2, y=sizey * 2},
                collisionbox = {-thickness, -sizey, -sizez, thickness, sizey, sizez},
               
            })
            marker:get_luaentity():queue_delete(duracion);
            marker:set_yaw(math.pi / 2)
            marker:get_luaentity().player_name = name

            table.insert(markers, marker)
        end
    end

    -- --------------------------------
    
    -- local obj = minetest.add_entity(pointed_thing.under, "areahelper_planner:markerentity", nil);

    --[[obj:set_properties({
        visual_size = {x = 16, y = 16},
        textures = {
            "square_blue.png"
        },
        paramtype = "light",
        sunlight_propagates = true,
        nametag = "caja marcadora",
        nametag_color = "red",
        nametag_bgcolor = "yellow",
        static_save = false -- Para que no se persista en unload
    });
    ]]--
end

minetest.register_craft({
    output = "areahelper_planner:areaplanner",
    type = "shapeless",
    recipe = {
        "dye:red",      "dye:green", "dye:blue" , "dye:black", "dye:white",
        "default:book"
        }
    
})

-- --- template_written -------------------------------------


local function place_secondary_writen(itemstack, player, pointed_thing)
    -- PREPARA EL MARCADOR
    local metas = itemstack:get_meta();
    local pos1, pos2 = calcularPosiciones(player, { ancho = metas:get_string("ancho")
            , largo = metas:get_string("largo")
            , alto = metas:get_string("alto")
            , soterrado = metas:get_string("soterrado")}
        )

    local formNombre = {
        areahelper.dimensionformspec,
        "label[0.375,0.50;", minetest.formspec_escape("TAL QUE PASA"), "]",
        "field[0.375,1.25;6 ,0.8;nombre;Nombre para el area;]",
        "button_exit[4.5,5;3,0.8;setear;Setear]"
    };
    local s = minetest.show_formspec(player:get_player_name(), "areahelper_planner:nameform", table.concat(formNombre, ""));
    
    -- ###### REALIZA EL AREA #############
    local salida, mensaje = areahelper:realizarArea(player:get_player_name(), pos1, pos2, "")
    if not salida then
        minetest.chat_send_player(player, mensaje);
        return itemstack;
    end
    generateMarker(pos1, pos2, TIME_DURATIONS.LONG);


    -- actualizar el inventario
    itemstack:take_item(1); -- se disminuye y se pierde.
    return itemstack;

end

minetest.register_on_player_receive_fields(function(player, formname, fields)
    
    -- GUARDAS
    if formname ~= "areahelper_planner:nameform" then return; end

    -- Fields contendría el nombre para el area.
    minetest.log(fields.nombre)
    -- Instanciar el stack del item de plantilla para obtener el meta (calcular las posiciones...) 



end)

minetest.register_craftitem("areahelper_planner:template_writen",{
    description = "Plantilla con un area anotada.",
    groups = { not_in_creative_inventory = 1, areahelper = 1, tool = 1},
    inventory_image = imgtemplatewritten,
    on_place = function(itemstack, placer, pointed_thing)
       return place_secondary_writen(itemstack, placer, pointed_thing)

    end,
    on_secondary_use = function(itemstack, user, pointed_thing) 
        return place_secondary_writen(itemstack, user, pointed_thing)
    end,
    on_use = function(itemstack, user, pointed_thing) 
        -- TODO MOSTRAR EL AREA COMO PRUEBA.
        local metas = itemstack:get_meta();
        local pos1, pos2 = calcularPosiciones(user, 
            { ancho = metas:get_string("ancho")
                , largo = metas:get_string("largo")
                , alto  = metas:get_string("alto")
                , soterrado = metas:get_string("soterrado")
            })
        generateMarker(pos1, pos2, TIME_DURATIONS.SHORT);
        -- No modificar el stack
        return itemstack;
    end,
    
});

default.register_craft_metadata_copy("default:paper", "areahelper_planner:template_writen")


local function tal()

    -- ¿DEVUELVEN AQUI LA INFO?
        -- GENERAR UN OBJETO _writen CON LOS METADATOS -> darselo a si user tiene espacio o desprenderlo
        local newItem = ItemStack({name="areahelper:template_writen", count = 5, wear = 0});
        newItem:get_meta():set_string("description", "CADENA ANOTADA");

        if inv:room_for_item("main" , newItem) then 
            -- HAY SITIO AÑADIR NEW ITEM.
            minetest.log([[Creando
            ]] .. dump(newItem == nil) .. [[
                
            ]] .. newItem:get_count() .. " " .. newItem:get_name() .. " " .. newItem:get_description() .. " " .. newItem:get_meta():get_string("tal"));
            
            --Creando" .. "" ..  ""  .. dump(newItem == nil));
            -- DISMINUIR EN UNO EL STACK DE TEMPLATE
            
        else
          
        end
end